use std::error::Error;

use alloy_sol_types::{SolValue, abi::TokenSeq};
use ucs03_zkgm::com::{TAG_ACK_FAILURE, TAG_ACK_SUCCESS};
use unionlabs_primitives::{Bytes, H256, U256};

pub use crate::{
    batch::{Batch, BatchAck, BatchShape},
    call::{Call, CallAck, CallShape},
    forward::{Forward, ForwardAck, ForwardShape},
    root::{Root, RootAck, RootShape},
    token_order::{TokenOrder, TokenOrderAck, TokenOrderShape},
};

pub mod batch;
pub mod call;
pub mod forward;
pub mod root;
pub mod token_order;

pub type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync + 'static>>;

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(deny_unknown_fields, rename_all = "snake_case")
)]
pub struct ZkgmPacket {
    pub salt: H256,
    pub path: U256,
    pub instruction: Root,
}

impl ZkgmPacket {
    pub fn decode(bz: impl AsRef<[u8]>) -> Result<Self> {
        let ucs03_zkgm::com::ZkgmPacket {
            salt,
            path,
            instruction,
        } = ucs03_zkgm::com::ZkgmPacket::abi_decode_params_validate(bz.as_ref())?;

        Ok(Self {
            salt: salt.into(),
            path: path.into(),
            instruction: Root::from_raw(instruction)?,
        })
    }

    pub fn encode(self) -> Bytes {
        ucs03_zkgm::com::ZkgmPacket::abi_encode_params(&ucs03_zkgm::com::ZkgmPacket {
            salt: self.salt.into(),
            path: self.path.into(),
            instruction: self.instruction.into_instruction().into_raw(),
        })
        .into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(deny_unknown_fields, rename_all = "snake_case")
)]
pub enum Ack {
    Success(RootAck),
    Failure(Bytes),
}

impl Ack {
    pub fn decode(shape: RootShape, bz: impl AsRef<[u8]>) -> Result<Self> {
        let ucs03_zkgm::com::Ack { tag, inner_ack } =
            ucs03_zkgm::com::Ack::abi_decode_params_validate(bz.as_ref())?;

        match tag {
            TAG_ACK_SUCCESS => RootAck::decode(shape, &inner_ack).map(Ack::Success),
            TAG_ACK_FAILURE => Ok(Ack::Failure(inner_ack.into())),
            invalid => Err(format!("invalid ack tag {invalid}"))?,
        }
    }

    pub fn encode(&self) -> Bytes {
        match self {
            Ack::Success(inner_ack) => ucs03_zkgm::com::Ack {
                tag: TAG_ACK_SUCCESS,
                inner_ack: inner_ack.encode().into(),
            }
            .abi_encode_params()
            .into(),
            Ack::Failure(inner_ack) => ucs03_zkgm::com::Ack {
                tag: TAG_ACK_FAILURE,
                inner_ack: inner_ack.clone().into(),
            }
            .abi_encode_params()
            .into(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(deny_unknown_fields, rename_all = "snake_case")
)]
pub struct Instruction {
    opcode: u8,
    version: u8,
    operand: Bytes,
}

impl Instruction {
    pub(crate) fn new<
        S: for<'a> SolValue<SolType: alloy_sol_types::SolType<Token<'a>: TokenSeq<'a>>>,
    >(
        opcode: u8,
        version: u8,
        operand: S,
    ) -> Self {
        Self {
            opcode,
            version,
            operand: S::abi_encode_params(&operand).into(),
        }
    }

    pub(crate) fn into_raw(self) -> ucs03_zkgm::com::Instruction {
        ucs03_zkgm::com::Instruction {
            version: self.version,
            opcode: self.opcode,
            operand: self.operand.into(),
        }
    }
}

#[cfg(test)]
mod tests {
    use hex_literal::hex;

    use super::*;
    use crate::{
        batch::{
            BatchInstructionV0, BatchInstructionV0Ack, BatchInstructionV0Shape, BatchV0,
            BatchV0Ack, BatchV0Shape,
        },
        call::{CallShape, CallV0, CallV0Ack, CallV0Shape},
        token_order::{TokenOrderShape, TokenOrderV1, TokenOrderV1Ack},
    };

    #[test]
    fn decode() {
        let packet = hex!(
            "79176e1d5f2779e14b2f5f885bfe7b35e78802643522ce0dad5cac4e4a44271f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000066000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000001415ee7c367f4232241028c36e720803100757c6e9000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e62626e316d377a72356a77346b397a32327239616a676766347563616c7779377578767539676b7736746e736d7634326c766a706b7761736167656b356700000000000000000000000000000000000000000000000000000000000000000014e53dcec07d16d88e386ae0710e86d9a400f83c31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000442414259000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007426162796c6f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047562626e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001415ee7c367f4232241028c36e720803100757c6e9000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e62626e316d377a72356a77346b397a32327239616a676766347563616c7779377578767539676b7736746e736d7634326c766a706b7761736167656b3567000000000000000000000000000000000000000000000000000000000000000000b27b22626f6e64223a7b22616d6f756e74223a223130303030222c2273616c74223a22307833313333303831396135613232336439376163373134663239616535653361646265396565663833383233373830663761393063636536363461626138366565222c226578706563746564223a2239373237222c22726563697069656e74223a2262626e3168637533306461647770686638397533783375366a327a35387233376339616b687866637330227d7d0000000000000000000000000000"
        );

        let ack = hex!(
            "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000b0cad00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001"
        );

        let expected_packet = ZkgmPacket {
            salt: hex!(
                "79176e1d5f2779e14b2f5f885bfe7b35e78802643522ce0dad5cac4e4a44271f"
            ).into(),
            path: U256::ZERO,
            instruction: Root::Batch(Batch::V0(BatchV0 {
                instructions: vec![
                    BatchInstructionV0::TokenOrder(TokenOrder::V1(TokenOrderV1 {
                        sender: hex!("15ee7c367f4232241028c36e720803100757c6e9").into(),
                        receiver: b"bbn1m7zr5jw4k9z22r9ajggf4ucalwy7uxvu9gkw6tnsmv42lvjpkwasagek5g"
                            .into(),
                        base_token: hex!("e53dcec07d16d88e386ae0710e86d9a400f83c31").into(),
                        base_amount: U256::from(10000_u64),
                        base_token_symbol: "BABY".to_owned(),
                        base_token_name: "Babylon".to_owned(),
                        base_token_decimals: 6,
                        base_token_path: U256::from(1_u64),
                        quote_token: b"ubbn".into(),
                        quote_amount: U256::from(10000_u64),
                    })),
                    BatchInstructionV0::Call(Call::V0(CallV0 {
                        sender: hex!("15ee7c367f4232241028c36e720803100757c6e9").into(),
                        eureka: false,
                        contract_address:
                            b"bbn1m7zr5jw4k9z22r9ajggf4ucalwy7uxvu9gkw6tnsmv42lvjpkwasagek5g".into(),
                        contract_calldata: br#"{"bond":{"amount":"10000","salt":"0x31330819a5a223d97ac714f29ae5e3adbe9eef83823780f7a90cce664aba86ee","expected":"9727","recipient":"bbn1hcu30dadwphf89u3x3u6j2z58r37c9akhxfcs0"}}"#.into()
                    })),
                ],
            })),
        };

        let decoded_packet = ZkgmPacket::decode(packet).unwrap();

        assert_eq!(decoded_packet, expected_packet);

        assert_eq!(<Bytes>::from(packet), decoded_packet.clone().encode());

        let expected_shape = RootShape::Batch(batch::BatchShape::V0(BatchV0Shape {
            instructions: vec![
                BatchInstructionV0Shape::TokenOrder(TokenOrderShape::V1),
                BatchInstructionV0Shape::Call(CallShape::V0(CallV0Shape { eureka: false })),
            ],
        }));

        let shape = decoded_packet.instruction.shape();

        assert_eq!(shape, expected_shape);

        let ack = Ack::decode(decoded_packet.instruction.shape(), ack).unwrap();

        let expected_ack = Ack::Success(RootAck::Batch(BatchAck::V0(BatchV0Ack {
            acknowledgements: vec![
                BatchInstructionV0Ack::TokenOrder(TokenOrderAck::V1(TokenOrderV1Ack::Protocol)),
                BatchInstructionV0Ack::Call(CallAck::V0(CallV0Ack::NonEureka)),
            ],
        })));

        assert_eq!(ack, expected_ack);
    }

    #[test]
    fn decode2() {
        let packet = hex!(
            "9e80e937663c3ba2e97e986aa83ae43c00c1d8a7e0fbbbe21642da0a35a012b70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000017e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007e00000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000001406627714f3f17a701f7074a12c02847a5d2ca4870000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e316d74786b38746a7a3835727932613861366b35387577727a746d77736c61787a73757268356c30646c78683777726e766d786b7368716b7577640000000000000000000000000000000000000000000000000000000000000014ba5ed44733953d79717f6269357c77718c8ba5ed0000000000000000000000000000000000000000000000000000000000000000000000000000000000000002617500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040756e696f6e3175757575757575757539756e3271706b73616d37726c747470786338646337366d63706868736d70333970786a6e737672746371767976353772000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001406627714f3f17a701f7074a12c02847a5d2ca4870000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e316d74786b38746a7a3835727932613861366b35387577727a746d77736c61787a73757268356c30646c78683777726e766d786b7368716b75776400000000000000000000000000000000000000000000000000000000000002017b22636f6e7472616374223a2230783735366536393666366533313634333237323334363536333733373536313730333437303735366137323663363633333665376133303339373637613338363536383631333837393330376133323335366236653731333036633636373837613334373937613665333833333736333636623731333036613738373336643662222c226d7367223a2265794a696232356b496a7037496d3170626e5266644739665957526b636d567a63794936496a42344e7a55325a5459354e6d59325a544d784e6d51334e4463344e6d497a4f4463304e6d453359544d344d7a55334d6a63354d7a49324d544d344e6a457a4e6a5a694d7a557a4f4463314e7a63334d6a64684e7a51325a4463334e7a4d32597a59784e7a67335954637a4e7a55334d6a59344d7a5532597a4d774e6a5132597a63344e6a677a4e7a63334e7a49325a5463324e6d51334f445a694e7a4d324f4463784e6d49334e5463334e6a51694c434a746157356662576c756446396862573931626e51694f6949784d4441774d4441774d4441774d4441774d4441774d444177496e3139222c2266756e6473223a5b7b2264656e6f6d223a226175222c22616d6f756e74223a2231303030303030303030303030303030303030227d5d2c2263616c6c5f616374696f6e223a2263616c6c5f6f6e5f70726f78795f63616c6c227d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001406627714f3f17a701f7074a12c02847a5d2ca4870000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e316d74786b38746a7a3835727932613861366b35387577727a746d77736c61787a73757268356c30646c78683777726e766d786b7368716b75776400000000000000000000000000000000000000000000000000000000000001507b22636f6e7472616374223a2230783735366536393666366533313635373536353735363537353635373533393736363137323334373936383634373237353739376136623661363337333638333733343738376136353735363733363633366237393739333633303638373333303736363337313665376137313663333236383731333036633738363333323636222c226d7367223a2265794a70626d4e795a57467a5a5639686247787664324675593255694f6e73696333426c626d526c63694936496a42344e575a695a546330595449344d3259334f5455305a6a4577595745774e474d795a57526d4e5455314e7a67344d5446685a5749774d794973496d46746233567564434936496a45774d4441774d4441774d4441774d4441774d4441774d4441696658303d222c2266756e6473223a5b5d2c2263616c6c5f616374696f6e223a22646972656374227d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001406627714f3f17a701f7074a12c02847a5d2ca4870000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e316d74786b38746a7a3835727932613861366b35387577727a746d77736c61787a73757268356c30646c78683777726e766d786b7368716b7577640000000000000000000000000000000000000000000000000000000000000ad67b22636f6e7472616374223a22756e696f6e313333366a6a386572746c3868377264766e7a3464683572716168643039637930783433677568737878367879727a747832393271706536346668222c226d7367223a2265794a7a5a57356b496a7037496e4268644767694f6949774969776959326868626d356c624639705a4349364d6a4173496e52706257567664585266614756705a326830496a6f694d434973496e5270625756766458526664476c745a584e3059573177496a6f694d5463314e7a45334e4463354f44597a4e6a41774d4441774d434973496e4e68624851694f69497765444a6b5a47466d4f475a68596a49795a474535595751354f47526d5a6d5a6a4e544d325a4449784d545932595749354f44646a4e4751314d44526d4d6a466d4e574d354d7a49314d54566c4d4441325a54466c4d5745694c434a70626e4e30636e566a64476c7662694936496a42344d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d6a41774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d444d774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4459774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d444d774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441784d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d5459774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4446684d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d44426b5a5442694e6d497a595463324e4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d6a41774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d47526c4d474932596a4e684e7a59304d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d444d774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d6a51774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d444179597a63314e6d55324f545a6d4e6d557a4d5463354e6d4d324e6a63794e6a67334d7a4d794e7a6b7a4e5464684e6a513259544d794d7a4d7a4f544d304e6d517a4e6a59324e7a67324e7a63774e3245334d6a5a684e6a45334e6a4d334e6d4d324e544d7a4e32457a4d444d334e6d45324e6a59324e7a45774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441784e4441324e6a49334e7a45305a6a4e474d5464684e7a41785a6a63774e7a52684d544a444d4449344e4464684e555179513245304f4463774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4451774e7a55325a5459354e6d59325a544d784e6a55334e5459314e7a55324e5463314e6a55334e544d354e7a59324d5463794d7a51334f5459344e6a51334d6a63314e7a6b3359545a694e6d45324d7a637a4e6a677a4e7a4d304e7a6733595459314e7a55324e7a4d324e6a4d32596a63354e7a6b7a4e6a4d774e6a67334d7a4d774e7a59324d7a63784e6d5533595463784e6d4d7a4d6a59344e7a457a4d445a6a4e7a67324d7a4d794e6a59774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4445305a5456445a6a457a517a6730597a426d5257457a4d6a4d32517a45774d554a6b4e3251334e444e6b4d7a417a4e6a5a464e554e474d5441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d444177595441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4451774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441344d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d54526c4e574e6d4d544e6a4f44526a4d475a6c59544d794d7a5a6a4d544178596d51335a4463304d32517a4d444d324e6d5531593259784d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d4441774d434a3966513d3d222c2266756e6473223a5b5d2c2263616c6c5f616374696f6e223a22646972656374227d00000000000000000000"
        );

        let ack = hex!(
            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000"
        );

        let decoded_packet = ZkgmPacket::decode(packet).unwrap();

        dbg!(&decoded_packet);

        let shape = decoded_packet.instruction.shape();

        dbg!(&shape);

        let ack = Ack::decode(decoded_packet.instruction.shape(), ack).unwrap();

        dbg!(&ack);

        println!("{}", serde_json::to_string_pretty(&decoded_packet).unwrap());
        println!("{}", serde_json::to_string_pretty(&shape).unwrap());
        println!("{}", serde_json::to_string_pretty(&ack).unwrap());
    }
}
